package com.capgemini.gae.daos;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;

import com.capgemini.gae.data.Athlete;
import com.capgemini.gae.data.Performance;
import com.capgemini.gae.data.Person;
import com.capgemini.gae.data.Trainer;
import com.google.appengine.api.datastore.Key;

public class PersonDao extends Dao<Person> {

	public Person save(Person type) {
		EntityManager em = EntityManagerFactoryHolder.get()
				.createEntityManager();
		EntityTransaction tx = em.getTransaction();
		Person temp = null;
		try {
			tx.begin();
			if ((type.getId() != null)) {
				temp = em.find(type.getEntityClass(), type.getKey());
			}
			if (type.getAdress() != null) {
				type.getAdress().setPerson(type);
			}
			if (type.getClass().equals(Athlete.class)) {
				// Performances must be persisted using TournamentDao
				Set<Key> perfs = ((Athlete) type).getPerformances();
				Performance tempperf = null;
				for (Key tempperfkey : ((Athlete) type).getPerformances()) {
					tempperf = em.find(Performance.class, tempperfkey);
					tempperf.setAthlete((Athlete) type);
					tempperf = em.merge(tempperf);
				}
				Trainer temptrain = null;
				for (Key temptrainkey : ((Athlete) type).getTrainers()) {
					temptrain = em.find(Trainer.class, temptrainkey);
					if (!((Trainer) temptrain).getAthletes().contains(type)) {
						temptrain.addAthletes((Athlete) type);
						temptrain = em.merge(temptrain);
					}
				}

			} else {
				Athlete tempath = null;
				for (Key tempathkey : ((Trainer) type).getAthletes()) {
					tempath = em.find(Athlete.class, tempathkey);
					if (!((Athlete) tempath).getTrainers().contains(type)) {
						tempath.addTrainer((Trainer) type);
						tempath = em.merge(tempath);
					}
				}

			}
			if (temp == null) {
				em.persist(type);
			} else {
				// if previous version already in database
				type = em.merge(type);
			}

			tx.commit();

			return type;
		} finally {
			if (tx.isActive()) {
				tx.rollback();
			}

			em.close();
		}
	}

	// delete certain person from database
	@SuppressWarnings("unchecked")
	@Override
	public void delete(Person type) {
		EntityManager em = EntityManagerFactoryHolder.get()
				.createEntityManager();
		EntityTransaction tx = em.getTransaction();
		try {
			tx.begin();
			Set<Key> atltrai = new HashSet<Key>();
			if (type.getClass().equals(Trainer.class)) {
				atltrai = ((Trainer) type).getAthletes();
			} else {
				atltrai = ((Athlete) type).getTrainers();
			}
			type = em.find(type.getEntityClass(), type.getKey());

			if (type.getClass().equals(Athlete.class)) {
				Performance tempperf = null;
				for (Key tempperfkey : ((Athlete) type).getPerformances()) {
					tempperf = em.find(Performance.class, tempperfkey);
					tempperf.setAthlete(null);
					tempperf = em.merge(tempperf);
				}
				Trainer temptrain = null;
				for (Key temptrainkey : atltrai) {
					temptrain = em.find(Trainer.class, temptrainkey);
					temptrain.getAthletes().remove(type.getKey());
					temptrain = em.merge(temptrain);
				}
			} else {
				Athlete tempath = null;
				for (Key tempathkey : atltrai) {
					tempath = em.find(Athlete.class, tempathkey);
					tempath.getTrainers().remove(type.getKey());
					tempath = em.merge(tempath);
				}
			}
			em.remove(type);
			tx.commit();
		} finally {
			if (tx.isActive()) {
				tx.rollback();
			}
			em.close();
		}
	}
}
